<?php
namespace app\index\controller;

use Hanson\Vbot\Foundation\Vbot;
use Hanson\Vbot\Message\Text;
use Illuminate\Support\Collection;
use think\facade\Env;
use util\Log;
use util\Tulin;

class Boot
{

    // private $worker;
    private $options; //配置文件

    /**
     *
     * @param [type] $session_id
     * @param [type] $pid
     */
    public function __construct($session_id, $pid)
    {
        //配置文件
        $path = Env::get('runtime_path') . 'boot_tmp/';

        $this->options = [

            'path' => $path,
            /*
             * swoole 配置项（执行主动发消息命令必须要开启，且必须安装 swoole 插件）
             */
            'swoole' => [
                'status' => false,
                'ip' => '127.0.0.1',
                'port' => '8866',
            ],
            /*
             * 下载配置项
             */
            'download' => [
                'image' => true,
                'voice' => true,
                'video' => true,
                'emoticon' => true,
                'file' => true,
                'emoticon_path' => $path . 'emoticons', // 表情库路径（PS：表情库为过滤后不重复的表情文件夹）
            ],
            /*
             * 输出配置项
             */
            'console' => [
                'output' => true, // 是否输出
                'message' => true, // 是否输出接收消息 （若上面为 false 此处无效）
            ],
            /*
             * 日志配置项
             */
            'log' => [
                'level' => 'debug',
                'permission' => 0777,
                'system' => $path . 'log', // 系统报错日志
                'message' => $path . 'log', // 消息日志
            ],
            /*
             * 缓存配置项
             */
            'cache' => [
                'default' => 'file', // 缓存设置 （支持 redis 或 file）
                'stores' => [
                    'file' => [
                        'driver' => 'file',
                        'path' => $path . 'cache',
                    ],
                    'redis' => [
                        'driver' => 'redis',
                        'connection' => 'default',
                    ],
                ],
            ],
            /*
             * 拓展配置
             * ==============================
             * 如果加载拓展则必须加载此配置项
             */
            'extension' => [
                // 管理员配置（必选），优先加载 remark_name
                'admin' => [
                    'remark' => '',
                    'nickname' => '',
                ],
            ],

            //定义配置文件 传递的参数
            'session_id' => $session_id,
            'pid' => $pid,
        ];
        //$this->worker = $worker;
        //  $this->options['session_id'] = $session_id;
        //  $this->options['pid'] = $pid;
    }

    /**
     * windows下运行
     *
     * @return void
     */
    public function run()
    {
        //配置文件
        $path = Env::get('runtime_path') . 'boot_tmp/';
        $options = [
            'path' => $path,
            /*
             * swoole 配置项（执行主动发消息命令必须要开启，且必须安装 swoole 插件）
             */
            'swoole' => [
                'status' => false,
                'ip' => '127.0.0.1',
                'port' => '8866',
            ],
            /*
             * 下载配置项
             */
            'download' => [
                'image' => true,
                'voice' => true,
                'video' => true,
                'emoticon' => true,
                'file' => true,
                'emoticon_path' => $path . 'emoticons', // 表情库路径（PS：表情库为过滤后不重复的表情文件夹）
            ],
            /*
             * 输出配置项
             */
            'console' => [
                'output' => true, // 是否输出
                'message' => true, // 是否输出接收消息 （若上面为 false 此处无效）
            ],
            /*
             * 日志配置项
             */
            'log' => [
                'level' => 'debug',
                'permission' => 0777,
                'system' => $path . 'log', // 系统报错日志
                'message' => $path . 'log', // 消息日志
            ],
            /*
             * 缓存配置项
             */
            'cache' => [
                'default' => 'file', // 缓存设置 （支持 redis 或 file）
                'stores' => [
                    'file' => [
                        'driver' => 'file',
                        'path' => $path . 'cache',
                    ],
                    'redis' => [
                        'driver' => 'redis',
                        'connection' => 'default',
                    ],
                ],
            ],
            /*
             * 拓展配置
             * ==============================
             * 如果加载拓展则必须加载此配置项
             */
            'extension' => [
                // 管理员配置（必选），优先加载 remark_name
                'admin' => [
                    'remark' => '',
                    'nickname' => '',
                ],
            ],
        ];

        //开启机器人
        $vbot = new Vbot($options);
        // 获取监听器实例
        $observer = $vbot->observer;
        //二维码监听器
        $observer->setQrCodeObserver(function ($qrCodeUrl) {
            Log::info('qrCodeUrl' . $qrCodeUrl);
            Log::info('当前进程' . PID);
            //生成二维码
            $params = PARAMS;
            $session_id = $params[1];
            if ($session_id) {
                Log::info('当前session_id:' . $session_id);
                $result['code'] = 1;
                $result['qrCodeUrl'] = $qrCodeUrl;
                cache($session_id, $result, 600);
            } else {
                $result['code'] = -1;
                $result['msg'] = '未获取到session_id';
                cache($session_id, $result, 600);
            }
        });

        //免扫码登录成功时回调。
        $observer->setReLoginSuccessObserver(function () {
            Log::info('免扫码登录');
        });

        //登录成功时回调。无论是第一次登录还是免扫码登录均会触发。
        $observer->setLoginSuccessObserver(function () {
            $myself = vbot('myself');
            //$groups = vbot('groups');
            //Log:info('login_groups' . gettype($groups));
            Log::info('登录成功，当前用户昵称: ' . $myself->nickname . ',用户uin: ' . $myself->uin . '用户sex:' . $myself->sex);
            Log::info('无论是第一次登录还是免扫码登录均会触发');
        });

        //程序退出时回调。
        $observer->setExitObserver(function () {
            $params = PARAMS; //定义的常量
            $session_id = $params['1'];
            cache('user_info' . $session_id, null); // 清除用户缓存信息
            Log::info('程序正常退出');
        });

        //好友监听器  此回调仅在初始化好友时执行。
        //变量 $contacts 含有数组下表 ‘friends’,’groups’,’officials’,’special’,’members’
        $observer->setFetchContactObserver(function (array $contacts) {
            $myself = vbot('myself');
            $groups = vbot('groups');
            // $groups = $contacts['groups'];
            // $members = $contacts['members'];
            // Log::info('members' . var_export(json_decode($members->toJson(), true), true));
            // Log::info('groups' . var_export(json_decode($groups->toJson(), true), true));
            //记录自己的数据到数据库中
            //判断用户是否存在
            $params = PARAMS; //定义的常量
            $session_id = $params['1'];
            cache('login' . $session_id, null); //清除缓存
            $user = new User();
            $user_res = $user->initUserInfo($myself, $groups, $session_id, PID); //调用初始化用户方法
            if (is_int($user_res) && $user_res == -1) {
                $result['code'] = -1;
                $result['msg'] = '程序异常';
                cache('login' . $session_id, $result, 600);
            } else {
                $result['code'] = 1;
                $result['msg'] = '用户登录成功';
                cache('login' . $session_id, $result, 600);
            }
        });
        //当接收消息异常时，当系统判断为太久没从手机端打开微信时，则急需打开，时间过久将断开。
        $observer->setNeedActivateObserver(function () {
            $params = PARAMS; //定义的常量
            $session_id = $params['1'];
            cache('user_info' . $session_id, null); //清除用户缓存信息
            Log::info('消息异常或断开');
        });

        //处理消息
        $vbot->messageHandler->setHandler(function (Collection $message) {
            $myself = vbot('myself');
            $groups = vbot('groups'); //获取群成员
            // $friends = vbot('friends');
            //  $members = vbot('members');
            //  Log::info('groups' . var_export(json_decode($groups->toJson(), true), true));
            //  $groups_result = $groups->getUsernameByNickname($message['from']['NickName'], $blur = false);
            //  Log::info('groups_result' . gettype($groups_result) . '//' . var_export(json_decode($groups_result->toJson(), true), true));
            $fromType = $message['fromType'];
            //判断消息发送者信息 System:系统消息 Self:自己发送的消息 Group:群组消息 Friend:联系人消息 Official:公众号消息 Special:特殊账号消息 Unknown:未知消息
            if ($fromType != 'System') {
                Log::info('message' . var_export($message, true));
            }
            //  根据昵称获取对象
            //  $nickname = $friends->getUsernameByNickname($message['from']['NickName'], $blur = false);
            //Log::info('nickname' . gettype($nickname));
            //根据备注获取对象
            // $remark = $friends->getUsernameByRemarkName($message['from']['RemarkName'], $blur = false);
            //  Log::info('remark' . gettype($remark));
            //搜索出 UserName
            //search 为搜索的词，key 为要搜索的键
            //  $friends->getUsername($search, $key, $blur = false);
            //搜索出 联系人
            //search 为搜索的词，key 为要搜索的键
            //  $friends->getUsername($search, $key, $blur = false);
            //根据 UserName 获取联系人
            /////当你无法得知该 username 所属时可使用
            // $account = $friends->getAccount($message['from']['UserName']);
            //  Log::info('account' . gettype($account) . var_export($account, true));
            //一般建议根据类型选择，如
            // $get = $groups->get($message['from']['UserName']);
            // Log::info('get' . gettype($get) . var_export($get, true));
            //获取头像
            // $data = $groups->getAvatar($username);
            // file_put_content('avatar.jpg', $data);
            switch ($fromType) {
                case 'Self':
                    //当主动发送消息，只有发送给文件助手才会恢复消息
                    if ($message['from']['UserName'] == 'filehelper') {
                        $this->sendMessageToSelf($message, $groups);
                    }
                    break;
                case 'Friend':
                    $this->sendMessageToFriend($message);
                    break;
                case 'Group':
                    //$nickname = $groups->getUsernameByNickname($message['from']['NickName'], $blur = false);
                    // Log::info('nickname' . gettype($nickname) . var_export($nickname, true));
                    //  $list = $groups->getGroupsByNickname($message['from']['NickName'], $blur = false);
                    // Log::info('list' . gettype($list) . var_export($list, true));
                    $this->sendMessageToGroup($message);
                    break;
            }
        });
        $vbot->server->serve();
    }

    /**
     * swoole调用该方法
     *
     * @param [type] $session_id
     * @param [type] $pid
     * @return void
     */
    public function boot_run()
    {

        //开启机器人
        $vbot = new Vbot($this->options);
        // 获取监听器实例
        $observer = $vbot->observer;
        //二维码监听器
        $observer->setQrCodeObserver(function ($qrCodeUrl) {
            Log::info('qrCodeUrl' . $qrCodeUrl);
            //Log::info('当前进程' . PID);
            Log::info('当前进程:' . $this->options['pid']);
            //生成二维码
            // $params = PARAMS;
            $session_id = $this->options['session_id'];
            if ($session_id) {
                Log::info('当前session_id:' . $session_id);
                $result['code'] = 1;
                $result['qrCodeUrl'] = $qrCodeUrl;
                cache($session_id, $result, 600);
            } else {
                $result['code'] = -1;
                $result['msg'] = '未获取到session_id';
                cache($session_id, $result, 600);
            }
        });

        //免扫码登录成功时回调。
        $observer->setReLoginSuccessObserver(function () {
            Log::info('免扫码登录');
        });

        //登录成功时回调。无论是第一次登录还是免扫码登录均会触发。
        $observer->setLoginSuccessObserver(function () {
            $myself = vbot('myself');
            //$groups = vbot('groups');
            //Log:info('login_groups' . gettype($groups));
            Log::info('登录成功，当前用户昵称: ' . $myself->nickname . ',用户uin: ' . $myself->uin . '用户sex:' . $myself->sex);
            Log::info('无论是第一次登录还是免扫码登录均会触发');
        });

        //程序退出时回调。
        $observer->setExitObserver(function () {
            //$params = PARAMS; //定义的常量
            // $session_id = $params['1'];
            $session_id = $this->options['session_id'];
            cache('user_info' . $session_id, null); // 清除用户缓存信息
            Log::info('程序正常退出');
            // $this->worker->write('程序退出');
        });

        //好友监听器  此回调仅在初始化好友时执行。
        //变量 $contacts 含有数组下表 ‘friends’,’groups’,’officials’,’special’,’members’
        $observer->setFetchContactObserver(function (array $contacts) {
            $myself = vbot('myself');
            $groups = vbot('groups');
            // $groups = $contacts['groups'];
            // $members = $contacts['members'];
            // Log::info('members' . var_export(json_decode($members->toJson(), true), true));
            //  Log::info('groups' . var_export(json_decode($groups->toJson(), true), true));
            //记录自己的数据到数据库中
            //判断用户是否存在
            //  $params = PARAMS; //定义的常量
            //  $session_id = $params['1'];
            $session_id = $this->options['session_id'];
            $pid = $this->options['pid'];
            cache('login' . $session_id, null); //清除缓存
            $user = new User();
            $user_res = $user->initUserInfo($myself, $groups, $session_id, $pid); //调用初始化用户方法
            if (is_int($user_res) && $user_res == -1) {
                $result['code'] = -1;
                $result['msg'] = '程序异常';
                cache('login' . $session_id, $result, 600);
            } else {
                $result['code'] = 1;
                $result['msg'] = '用户登录成功';
                cache('login' . $session_id, $result, 600);
            }
        });
        //当接收消息异常时，当系统判断为太久没从手机端打开微信时，则急需打开，时间过久将断开。
        $observer->setNeedActivateObserver(function () {
            //  $params = PARAMS; //定义的常量
            //  $session_id = $params['1'];
            $session_id = $this->options['session_id'];
            cache('user_info' . $session_id, null); //清除用户缓存信息
            Log::info('消息异常或断开');
        });

        //处理消息
        $vbot->messageHandler->setHandler(function (Collection $message) {
            $myself = vbot('myself');
            // $friends = vbot('friends');
            //  $members = vbot('members');
            //  Log::info('groups' . var_export(json_decode($groups->toJson(), true), true));
            //  $groups_result = $groups->getUsernameByNickname($message['from']['NickName'], $blur = false);
            //  Log::info('groups_result' . gettype($groups_result) . '//' . var_export(json_decode($groups_result->toJson(), true), true));
            $fromType = $message['fromType'];
            //判断消息发送者信息 System:系统消息 Self:自己发送的消息 Group:群组消息 Friend:联系人消息 Official:公众号消息 Special:特殊账号消息 Unknown:未知消息
            if ($fromType != 'System') {
                Log::info('message' . var_export($message, true));
            }
            //  根据昵称获取对象
            //  $nickname = $friends->getUsernameByNickname($message['from']['NickName'], $blur = false);
            //Log::info('nickname' . gettype($nickname));
            //根据备注获取对象
            // $remark = $friends->getUsernameByRemarkName($message['from']['RemarkName'], $blur = false);
            //  Log::info('remark' . gettype($remark));
            //搜索出 UserName
            //search 为搜索的词，key 为要搜索的键
            //  $friends->getUsername($search, $key, $blur = false);
            //搜索出 联系人
            //search 为搜索的词，key 为要搜索的键
            //  $friends->getUsername($search, $key, $blur = false);
            //根据 UserName 获取联系人
            /////当你无法得知该 username 所属时可使用
            // $account = $friends->getAccount($message['from']['UserName']);
            //  Log::info('account' . gettype($account) . var_export($account, true));
            //一般建议根据类型选择，如
            // $get = $groups->get($message['from']['UserName']);
            // Log::info('get' . gettype($get) . var_export($get, true));
            //获取头像
            // $data = $groups->getAvatar($username);
            // file_put_content('avatar.jpg', $data);
            switch ($fromType) {
                case 'Self':
                    //当主动发送消息，只有发送给文件助手才会恢复消息
                    if ($message['from']['UserName'] == 'filehelper') {
                        //  $groups = vbot('groups'); //获取群成员
                        $this->sendMessageToSelf($message);
                    }
                    break;
                case 'Friend':
                    $this->sendMessageToFriend($message);
                    break;
                case 'Group':
                    //$nickname = $groups->getUsernameByNickname($message['from']['NickName'], $blur = false);
                    // Log::info('nickname' . gettype($nickname) . var_export($nickname, true));
                    //  $list = $groups->getGroupsByNickname($message['from']['NickName'], $blur = false);
                    // Log::info('list' . gettype($list) . var_export($list, true));
                    $this->sendMessageToGroup($message);
                    break;
            }
        });
        $vbot->server->serve();
    }

    /**
     *发送消息给自己（文件助手）
     *
     * @param [type] $message
     * @return void
     */
    public function sendMessageToSelf($message)
    {

        Text::send($message['from']['UserName'], 'Hi, 我是文件助手');

    }

    /**
     *发送消息给朋友
     *
     * @param [type] $message
     * @return void
     */
    public function sendMessageToFriend($message)
    {

        $cache = cache($message['from']['UserName']);
        if ($cache) {
            //调用图灵机器人自动回复
            $this->autoApplyByTuLin($message, 'friend');

        } else {
            if ($message['message'] == '小可爱') {
                cache($message['from']['UserName'], 'enter');
                Text::send($message['from']['UserName'], "你的小可爱已经上线了！");
            } else {
                $hour = date('H', time());
                if ($hour > 23 || $hour < 7) {
                    Text::send($message['from']['UserName'], "主人正在睡觉中！\n如果实在无聊的话可以撩我，输入口令  小可爱  就可以跟我对话了！");
                } else {
                    //Text::send($message['from']['UserName'], "主人有事不在，你可以无视此消息！\n如果实在无聊的话可以撩我，输入口令  小可爱  就可以跟我对话了！");
                }
            }
        }
    }

    /**
     * 发送消息到组
     *
     * @param [type] $message
     * @return void
     */
    public function sendMessageToGroup($message)
    {
        $groups = vbot('groups'); //获取群成员
        // Log::info('message_groups' . var_export(json_decode($groups->toJson(), true), true));
        $user = new User();
        //通用方法查询聊天组是否有人数变化
        $result = $user->changeGroup($message);
        Log::info('change_group_result' . var_export($result, true));
        if (!is_int($result) && !empty($result)) {
            //通知机器人有人离开
            // Text::send('filehelper', $result['nickname'] . ' 退出 ' . $message['from']['NickName'] . ' 群聊');
            if ($result['type'] == 'add') {
                Text::send('filehelper', '欢迎 ' . $result['NickName'] . ' 进入' . $message['from']['NickName'] . ' 群聊');
            } else if ($result['type'] == 'remove') {
                // Text::send($message['from']['UserName'], $result['nickname'] . ' 退出此聊天群');
                Text::send('filehelper', $result['nickname'] . ' 退出 ' . $message['from']['NickName'] . ' 群聊');
            }
        }

        //判断群里是否有人@机器人
        if (strpos($message['message'], '@') !== false) {
            //调用机器人
            $this->autoApplyByTuLin($message, 'group');
        }

        switch ($message['type']) {
            case 'text':
                //Text::send($message['from']['UserName'], '有人说话了');
                break;
            case 'group_change':
                if ($message['action'] == 'ADD') {
                    //  $user->group_change_count($message, 'add');
                    //调用方法新增或者删除新增用户
                    // $get = $groups->get($message['from']['UserName']);
                    // Log::info('groups_type' . gettype($get) . ' ' . var_export($get, true));
                    // Log::info('new_groups' . var_export(json_decode($get->toJson(), true), true));
                    // Text::send($message['from']['UserName'], '欢迎新人 ' . $message['invited'] . PHP_EOL . '邀请人：' . $message['inviter']);
                    Text::send($message['from']['UserName'], '欢迎新人 ' . $message['invited'] . ' 进入群聊');
                } else if ($message['action'] == 'REMOVE') {
                    // $user->group_change_count($message, 'remove');
                    //  $get = $groups->get($message['from']['UserName']);
                    // Log::info('groups_type' . gettype($get) . ' ' . var_export($get, true));
                    Text::send($message['from']['UserName'], $message['message']);
                    // Text::send('filehelper', $message['from']['UserName'] . ':remove');
                }
                break;
        }
    }

    /**
     * 通过图灵机器人自动回复消息
     *
     * @param [type] $message
     * @return void
     */
    private function autoApplyByTuLin($message, $type)
    {
        if ($message['type'] == 'text') {
            $data['messType'] = 0;
        } else if ($message['type'] == 'image') {
            $data['messType'] = 1;
        } else if ($message['type'] == 'voice') {
            $data['messType'] = 2;
        } else {
            $data['messType'] = 2;
        }
        if ($type == 'friend') {
            $data['content'] = $message['message'];
            $data['userId'] = substr($message['from']['UserName'], 1);
        } else if ($type == 'group') {
            $data['content'] = $message['pure'];
            $data['userId'] = substr($message['sender']['UserName'], 1);
        }
        $data['selfInfo'] = [
            'location' => [
                'city' => get_address_by_ip(request()->ip()),
            ],
        ];
        // Log::info('data' . var_export($data, true));
        //调用图灵机器人
        $json = Tulin::getResult($data);
        $result = json_decode($json, true);
        if ($result['results'][0]['resultType'] == 'text') {
            $text = $result['results'][0]['values']['text'];
        } else if ($result['results'][0]['resultType'] == 'url') {
            $text = $result['results'][0]['values']['url'];
        }
        Text::send($message['from']['UserName'], $text);
    }

}
